package cem.agony.ui;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import cem.agony.model.SagStation;

public class StationPoint extends Parent
{
    public static class StationCell extends ListCell<StationPoint>
    {
        @Override
        public void updateItem( StationPoint item, boolean empty )
        {
            super.updateItem( item, empty );

            setText( item == null ? "" : item.getName() );
        }
    };
    
    public static final int SIZE = 20;

    private double startDragX;
    private double startDragY;
    private Point2D dragAnchor;

    private final Label nameLabel = new Label();

    private final Map<Integer, RoadPoint> fromRoads = new HashMap<Integer, RoadPoint>();
    private final Map<Integer, RoadPoint> toRoads = new HashMap<Integer, RoadPoint>();

    private final SagStation station;

    public StationPoint( SagStation station )
    {
        this.station = station;

        Rectangle rectangle = new Rectangle();
        rectangle.setWidth( SIZE );
        rectangle.setHeight( SIZE );
        rectangle.setFill( Color.LIGHTBLUE );

        nameLabel.setPrefWidth( 75 );
        nameLabel.setText( station.getName() );

        StackPane box = new StackPane();
        box.setAlignment( Pos.CENTER );
        box.getChildren().addAll( rectangle, nameLabel );

        getChildren().add( box );
        setFocusTraversable( true );

        setOnMousePressed( new EventHandler<MouseEvent>()
        {
            @Override
            public void handle( MouseEvent event )
            {
                toFront();
                startDragX = getTranslateX();
                startDragY = getTranslateY();
                dragAnchor = new Point2D( event.getSceneX(), event.getSceneY() );
            }
        } );
        setOnMouseDragged( new EventHandler<MouseEvent>()
        {
            @Override
            public void handle( MouseEvent event )
            {
                double newTranslateX = startDragX + event.getSceneX() - dragAnchor.getX();
                double newTranslateY = startDragY + event.getSceneY() - dragAnchor.getY();

                setTranslateX( newTranslateX );
                setTranslateY( newTranslateY );

                for ( RoadPoint road : fromRoads.values() )
                {
                    road.updateFromStation( newTranslateX + getCenterX(), newTranslateY +
                                                                          getCenterY() );
                }
                for ( RoadPoint road : toRoads.values() )
                {
                    road.updateToStation( newTranslateX + getCenterX(), newTranslateY +
                                                                        getCenterY() );
                }
            }
        } );
    }

    public double getCenterX()
    {
        return getBoundsInLocal().getWidth() / 2;
    }

    public double getCenterY()
    {
        return getBoundsInLocal().getHeight() / 2;
    }

    public void setName( String name )
    {
        nameLabel.setText( name );
        station.setName( name );
    }

    public String getName()
    {
        return station.getName();
    }

    /**
     * @returns road if a new road was created, null otherwise
     */
    public RoadPoint addFromRoad( StationPoint toStation, double distance )
    {
        station.addStation( toStation.getStation().getId(), distance );

        RoadPoint road = fromRoads.get( toStation.getStation().getId() );
        if ( road == null )
        {
            road = new RoadPoint( getTranslateX() + getCenterX(),
                                  getTranslateY() + getCenterY(),
                                  toStation.getTranslateX() + toStation.getCenterX(),
                                  toStation.getTranslateY() + toStation.getCenterY() );

            fromRoads.put( toStation.getStation().getId(), road );
            return road;
        }
        else
        {
            return null;
        }
    }

    /**
     * @returns road if a new road was created, null otherwise
     */
    public void addToRoad( StationPoint fromStation, RoadPoint road )
    {
        toRoads.put( fromStation.getStation().getId(), road );
    }

    public RoadPoint removeStation( int station )
    {
        toRoads.remove( station );
        this.station.removeStation( station );
        return fromRoads.remove( station );
    }

    public Collection<RoadPoint> getFromRoads()
    {
        return fromRoads.values();
    }

    public double getDistance( int station )
    {
        return this.station.getDistance( station );
    }

    public SagStation getStation()
    {
        return station;
    }
}